package myzd.services.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import libedge.domain.exceptions.GenericException;
import lombok.extern.slf4j.Slf4j;
import myzd.api.code.CodeUtils;
import myzd.client.WeChatQiYeClient;
import myzd.client.domain.AccessTokenResponse;
import myzd.client.domain.LoginTokenResponse;
import myzd.domain.QiYeEmployee;
import myzd.domain.Users;
import myzd.domain.response.Department;
import myzd.domain.response.UserInfo;
import myzd.domain.response.UserInfoResponse;
import myzd.mapper.UserMapper;
import myzd.services.ClientService;
import myzd.services.UserService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import retrofit2.Response;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zjm
 * @since 2017.10.23
 */
@Component
@Slf4j
public class DefaultUserServiceImpl implements UserService {
  @Autowired
  private ClientService clientService;
  @Autowired
  private WeChatQiYeClient weChatQiYeClient;
  @Autowired
  private UserMapper userMapper;
  @Value("${token.jwt.expire.seconds}")
  private Integer tokenJwtExpireSeconds;
  @Value("${source.intranet.secret}")
  private String sourceIntranetSecret;
  @Value("${qiye.config.agent}")
  private String qiyeConfigAgent;
  @Value("${qiye.config.client.id}")
  private String qiyeConfigClientId;
  @Value("${qiye.config.client.secret}")
  private String qiyeConfigClientSecret;
  @Value("${qiye.config.jwt.secret}")
  private String qiyeConfigJwtSecret;
  @Value("${qiye.config.user.in.service:true}")
  private boolean qiyeConfigUserInService;
  @Value("${qiye.config.user.departments}")
  private String qiyeConfigUserDepartments;
  @Value("${default.user.role}")
  private Long defaultUserRole;

  @Override
  public List<Department> getGroupList() throws GenericException {
    return clientService.getGroupList().getList();
  }

  @Override
  public List<QiYeEmployee> getUserList() throws GenericException, IOException {
    return StringUtils.isBlank(qiyeConfigUserDepartments) ?
      clientService.getUserList().getList() :
      getUserListByDepartment(
        Stream.of(qiyeConfigUserDepartments.split(","))
          .map(Integer::parseInt)
          .collect(Collectors.toList())
      );
  }

  private List<QiYeEmployee> getUserListByDepartment(List<Integer> departmentIds) throws IOException, GenericException {
    List<QiYeEmployee> qiYeEmployeeList = new ArrayList<>();
    for (Integer id :
      departmentIds) {
      qiYeEmployeeList.addAll(clientService.listUsersInDepartment(id, qiyeConfigUserInService).getList());
    }
    return qiYeEmployeeList;
  }

  @Override
  public AccessTokenResponse getUserAccessToken(String staffId) throws IOException, GenericException {
    QiYeEmployee qiYeEmployee = clientService.getUserByStaffId(staffId);
    UserInfo userInfo = new UserInfo();
    BeanUtils.copyProperties(qiYeEmployee, userInfo);
    userInfo.setStaffId(qiYeEmployee.getUserId());
    if (qiYeEmployee.getDepartments() != null && qiYeEmployee.getDepartments().size() >= 1) {
      userInfo.setDepartmentId(qiYeEmployee.getDepartments().get(0).getId());
      userInfo.setDepartmentName(qiYeEmployee.getDepartments().get(0).getName());
    }
    // 获取CRM的用户信息及权限信息
    Users users = userMapper.getUserByEmail(qiYeEmployee.getEmail());
    if (users == null) {
      log.info("create crm user [{}]", qiYeEmployee.getName());
      users = new Users();
      users.setEmail(qiYeEmployee.getEmail());
      users.setName(qiYeEmployee.getName());
      users.setMobile(qiYeEmployee.getMobile());
      users.setCreatedAt(new Date());
      users.setUpdatedAt(new Date());
      users.setPassword(RandomStringUtils.random(20, true, false));
      users.setRememberToken(null);
      userMapper.createUsers(users);
      // 若用户不存在, 创建用户时, 默认添加权限, 权限从配置中读取
      userMapper.createUserRole(users.getId(), defaultUserRole);
    }
    userInfo.setUserId(users.getId());
    Date nowDate = new Date();
    Date expire = DateUtils.addSeconds(nowDate, tokenJwtExpireSeconds);
    Algorithm algorithm = Algorithm.HMAC256(sourceIntranetSecret);
    String accessToken = JWT.create()
      .withExpiresAt(expire)
      .withClaim("sub", userInfo.getUserId())
      .withClaim("uid", userInfo.getStaffId())
      .withClaim("email", userInfo.getEmail())
      .withClaim("user", userInfo.getEmail())
      .withClaim("name", userInfo.getName())
      .withClaim("userName", userInfo.getName())
      .withClaim("mobile", userInfo.getMobile())
      .withClaim("avatar", userInfo.getAvatar())
      .withClaim("department", String.valueOf(userInfo.getDepartmentId()))
      .withClaim("staff_id", userInfo.getStaffId())
      .withIssuedAt(nowDate)
      .withNotBefore(nowDate)
      .withJWTId(RandomStringUtils.random(16))
      .sign(algorithm);
    return new AccessTokenResponse() {{
      setAccessToken(accessToken);
      setExpiresIn((int) (expire.getTime() / 1000));
    }};
  }


  @Override
  public UserInfoResponse getUserInfoByStaffId(String staffId) throws IOException, GenericException {
    return null;
  }

  @Override
  public AccessTokenResponse getUserAccessTokenByCode(String code) throws GenericException, IOException {
    Response<AccessTokenResponse> accessTokenResponse = weChatQiYeClient.accessToken(qiyeConfigAgent, code, qiyeConfigClientId, qiyeConfigClientSecret).execute();
    log.debug("accessTokenResponse: {}", accessTokenResponse);
    if (accessTokenResponse.isSuccessful()) {
      AccessTokenResponse accessToken = accessTokenResponse.body();
      if (accessToken == null) {
        throw new GenericException(CodeUtils.ERROR_QIYE_GET_TOKEN, CodeUtils.getErrText(CodeUtils.ERROR_QIYE_GET_TOKEN));
      }
      // 解token并获取员工信息
      String qiyeToken = accessToken.getAccessToken();
      Algorithm algorithm = Algorithm.HMAC256(qiyeConfigJwtSecret);
      DecodedJWT body = JWT.require(algorithm).build().verify(qiyeToken);
      return getUserAccessToken(body.getClaim("staff_id").asString());
    } else {
      log.error("get qiye wechat accessToken error. message: {}", accessTokenResponse.message());
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public LoginTokenResponse userSsoLogin(String ssoLogin, String url) throws GenericException {
    LoginTokenResponse loginTokenResponse = new LoginTokenResponse();
    loginTokenResponse.setToken(ssoLogin + "?redirect_uri=" + url + "/api/v1/callback&state=crm");
    return loginTokenResponse;
  }

}
